using System;
using System.Configuration;
using System.Collections.Generic;
using System.Reflection;
using System.Web;

using BizElements.BusinessLayer;
using BizElements.Web;

namespace BizElements.Web.UI
{
    /// <summary>Displays exception in a user-friendly form and logs it.</summary>
    public partial class ErrorFrm : System.Web.UI.Page
    {
        /// <summary>Try to initialize Page.UICulture to match culture defined in UserSession.UiCulture.</summary>
        protected override void InitializeCulture()
        {
            // All in try-catch to prevent infinite loops that may occur if ErrorFrm generates exception and then tries to handle it, causing it generate another exception.
            try
            {
                if (UserSession.UiCulture != null)
                    this.UICulture = UserSession.UiCulture.Name;
            }
            catch 
            { 
            }
        }

        protected void Page_Load(object sender, EventArgs e)
        {
            // All in try-catch to prevent infinite loops that may occur if ErrorFrm generates exception and then tries to handle it, causing it generate another exception.
            try
            {
                DontCacheCurrentPageOnBrowser();

                if (!IsPostBack)
                {
                    Exception error = GetLastError();
                    if (error != null)
                    {
                        string currentUser = GetUserName();
                        LogError(error, currentUser);
                        DisplayError(error, currentUser);
                    }
                }
            }
            catch
            {
            }
        }

        private void DontCacheCurrentPageOnBrowser()
        {
            Response.ExpiresAbsolute = Time.Now.Subtract(new TimeSpan(1, 0, 0, 0));
            Response.Expires = 0;
            Response.CacheControl = "no-cache";
        }

        public static void SetLastError(Exception error)
        {
            HttpContext.Current.Session["ErrorFrm.LastError"] = error;
        }

        #region Error controler.

        private static bool DetailsEnabled
        {
            get
            {
                string cfgEnabled = ConfigurationManager.AppSettings["ErrorFrm.DetailsEnabled"];
                return (cfgEnabled == "true") ? true : false;
            }
        }

        private static string GetUserName()
        {
            string userName = null;
            try
            {
                if (UserSession.Actor != null)
                    userName = UserSession.Actor.Name;
            }
            catch {}

            return userName;
        }

        private static Exception GetLastError()
        {
            Exception error = HttpContext.Current.Session["ErrorFrm.LastError"] as Exception;
            HttpContext.Current.Session.Remove("ErrorFrm.LastError");
            if (error != null)
            {
                if (error is HttpUnhandledException)
                {
                    HttpUnhandledException httpUnhandledError = (HttpUnhandledException)error;
                    if (httpUnhandledError.InnerException != null)
                        error = httpUnhandledError.InnerException;
                }

                if (error is TargetInvocationException)
                {
                    TargetInvocationException targetInvocationError = (TargetInvocationException)error;
                    if (targetInvocationError.InnerException != null)
                        error = targetInvocationError.InnerException;
                }
            }

            return error;
        }

        private static void LogError(Exception error, string currentUser)
        {
            Dictionary<string, object> properties;
            if (currentUser != null)
            {
                properties = new Dictionary<string, object>();
                properties.Add("ActorName", currentUser);
            }
            else
            {
                properties = null;
            }

            if (IsCriticalError(error))
                Log.CriticalAppError(error.GetType().Name, error.ToString(), properties);
            else
                Log.AppError(error.GetType().Name, error.ToString(), properties);
        }

        private static bool IsCriticalError(Exception error)
        {
            bool isCritical = false;
            if (error is System.Data.SqlClient.SqlException)
                isCritical = (error as System.Data.SqlClient.SqlException).Class >= 17;
            else if (error is System.Net.WebException)
                isCritical = true;

            return isCritical;
        }

        private static void DetermineErrorCategory(Exception error, out bool isBrokenRule, out bool isCritical, out bool isAppError)
        {
            if (error is BrokenRuleException)
            {
                isBrokenRule = true;
                isCritical = false;
                isAppError = false;
            }
            else if (IsCriticalError(error))
            {
                isBrokenRule = false;
                isCritical = true;
                isAppError = false;
            }
            else
            {
                isBrokenRule = false;
                isCritical = false;
                isAppError = true;
            }
        }

        #endregion

        #region Error UI.

        private void DisplayError(Exception error, string currentUser)
        { 
            bool isBrokenRule, isCritical, isAppError;
            DetermineErrorCategory(error, out isBrokenRule, out isCritical, out isAppError);
            if (isBrokenRule)
            {
                this.uiBrokenRulePnl.Visible = true;
                this.uiBrokenRuleDescription.Text = (error as BrokenRuleException).BrokenRules.ToString();
            }
            else if (isCritical)
            {
                this.uiCriticalPnl.Visible = true;
            }
            else if (isAppError)
            {
                this.uiAppErrorPnl.Visible = true;
            }

            this.uiDetailsPnl.Visible = DetailsEnabled;
            if (DetailsEnabled)
            {
                this.uiUserName.Text = currentUser;
                this.uiTime.Text = Time.Now.ToString();
                this.uiExceptionDetails.Text = error.ToString();
            }
        }

        #endregion
    }
}
